#include "wavread.h"
 
bool WaveReader::find_fmt()
{
    RIFFChunkHeader hd;
    long size = 0; // 读取一次Header实际读到的大小，用来判断是否读取完毕
    do {
        size = fread(&hd, 1, sizeof(RIFFChunkHeader), f);
        if (hd.size % 2 == 1) // 如果块大小为奇数则需要对齐
            hd.size++;
        // 判断当前块的ID是不是"fmt "
        if (strncmp((char *)&hd.id, "fmt ", 4) != 0)
            fseek(f, hd.size, SEEK_CUR); // 不是直接跳过这个块
        else
            break;
    } while (size >= 8);
    if (size < 8) // 实际读取不足8字节一般说明到了文件末尾
        return false;
    // 假设文件的format块小于等于sizeof(WaveFormatExtensible)
    // 因为有极少数的格式是有自己的标准的，其尺寸大于微软的WaveFormatExtensible
    fread(&fmtext, 1, hd.size, f);
    // 判断文件格式是否是PCM或者IEEE编码，也就是FormatTag是1或者3
    // 否则是编码过的格式，需要解码，我们不支持这种格式
    if (fmtext.FormatTag == 0xFFFE) {
        if (fmtext.SubFormat.D1 != 1 && fmtext.SubFormat.D1 != 3)
            return false;
    }
    else if (fmtext.FormatTag != 1 && fmtext.FormatTag != 3) {
        return false;
    }
    return true;
}
 
bool WaveReader::find_data()
{
    RIFFChunkHeader hd;
    long size = 0; // 同上
    do {
        size = fread(&hd, 1, sizeof(RIFFChunkHeader), f);
        if (hd.size % 2 == 1) // 查找data块过程中这个更加重要
            hd.size++;        // 因为如果是8bit或者24bit单声道的文件可能不对齐2字节
        if (strncmp((char *)&hd.id, "data", 4) != 0) // 同上
            fseek(f, hd.size, SEEK_CUR);
        else
            break;
    } while (size >= 8);
    if (size < 8)
        return false;
    fgetpos(f, &data_pos); // 获取实际数据的位置
    data_size = hd.size;   // 该块的大小即为数据的大小
    return true;
}
 
WaveReader::WaveReader()
{
    memset(&fmtext, 0, sizeof(WaveFormatExtensible));
    f = NULL;
    read_size = 0;
}
 
WaveReader::~WaveReader()
{
    if (f)
        fclose(f);
}
 
bool WaveReader::open_file(char *filename)
{
    f = fopen(filename, "rb");
    if (f) {
        RIFFHeader riff;
        fread(&riff, 1, sizeof(RIFFHeader), f); // 读取文件的RIFF头
        if (strncmp((char *)&riff.id, "RIFF", 4) != 0) // 判断是不是RIFF文件
            return false;
        if (strncmp((char *)&riff.type, "WAVE", 4) != 0) // 判断是不是WAVE文件
            return false;
        // 按照规范，fmt块是第一个块
        if (!find_fmt()) // 先找fmt块
            return false;
        if (!find_data()) // 再找data块
            return false;
        return true;
    }
    return false;
}
 
void WaveReader::close_file()
{
    // 清理和初始化必要内容
    if (f)
        fclose(f);
    memset(&fmtext, 0, sizeof(WaveFormatExtensible));
    f = NULL;
    data_pos = 0;
    data_size = 0;
    read_size = 0;
}
 
const WaveFormatExtensible &WaveReader::get_fmtext()
{
    return fmtext;
}
 
int WaveReader::read_data(void *buffer, unsigned int size)
{
    if (read_size >= data_size) { // 已经读完所有数据了
        memset(buffer, 0, size);  // 缓冲区置0
        return -1;
    }
    int result;
    // 已经读取的加上要读取的小于实际的数据大小，说明还没到末尾
    if (read_size + size < data_size) {
        result = fread(buffer, 1, size, f);
        read_size += result; // 累加实际读取的
    }
    // 否则说明还没有读取的字节数小于需要读取的字节数，即将读完
    else {
        memset(buffer, 0, size); // 全部清0处理
        result = fread(buffer, 1, data_size - read_size, f); // 读取剩下的
        read_size = data_size;
    }
    return result;
}
 
void WaveReader::reset()
{
    read_size = 0;
    fseek(f, data_pos, SEEK_SET); // 回到数据开始的地方
}